home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 676-700 / 684 / playsound / playsound.c < prev    next >
C/C++ Source or Header  |  1995-03-18  |  17KB  |  758 lines

  1. /*
  2. **    PlaySound - Double-buffered IFF-8SVX player
  3. **
  4. **    © Copyright 1992 by Olaf `Olsen' Barthel
  5. **        All Rights Reserved
  6. */
  7.  
  8.     /* System includes. */
  9.  
  10. #include <libraries/iffparse.h>
  11. #include <workbench/startup.h>
  12. #include <graphics/gfxbase.h>
  13. #include <exec/execbase.h>
  14. #include <dos/dosextens.h>
  15. #include <devices/audio.h>
  16. #include <exec/memory.h>
  17.  
  18.     /* Prototypes. */
  19.  
  20. #include <clib/iffparse_protos.h>
  21. #include <clib/exec_protos.h>
  22. #include <clib/alib_protos.h>
  23. #include <clib/dos_protos.h>
  24.  
  25.     /* `VHDR' header format. */
  26.  
  27. struct Voice8Header
  28. {
  29.     ULONG    oneShotHiSamples,    /* # samples in the high octave 1-shot part */
  30.         repeatHiSamples,    /* # samples in the high octave repeat part */
  31.         samplesPerHiCycle;    /* # samples/cycle in high octave, else 0 */
  32.     UWORD    samplesPerSec;        /* data sampling rate */
  33.     UBYTE    ctOctave,        /* # of octaves of waveforms */
  34.         sCompression;        /* data compression technique used */
  35.     LONG    volume;            /* playback nominal volume from 0 to Unity
  36.                      * (full volume). Map this value into
  37.                      * the output hardware's dynamic range.
  38.                      */
  39. };
  40.  
  41.     /* Audio channel indexes, including control channel. */
  42.  
  43. enum    {    AUDIO_LEFT, AUDIO_RIGHT, AUDIO_CONTROL, AUDIO_COUNT };
  44.  
  45.     /* If run from Shell, we accept two parameters:
  46.      *
  47.      *    Pattern        = The files to play
  48.      *    BufferSize    = The replay buffer size to use.
  49.      */
  50.  
  51. enum    {    ARG_PATTERN, ARG_BUFFERSIZE, ARG_COUNT };
  52.  
  53.     /* Channel allocation bits. */
  54.  
  55. #define LEFT0F  1
  56. #define RIGHT0F  2
  57. #define RIGHT1F  4
  58. #define LEFT1F  8
  59.  
  60.     /* Channel allocation masks (to separate the left from
  61.      * the right).
  62.      */
  63.  
  64. #define LEFT_MASK    (LEFT0F | LEFT1F)
  65. #define RIGHT_MASK    (RIGHT0F | RIGHT1F)
  66.  
  67.     /* Program version identifier. */
  68.  
  69. STATIC UBYTE *Version = "\0$VER: PlaySound 1.1 (27.4.92)";
  70.  
  71.     /* Shared libraries. */
  72.  
  73. struct ExecBase        *SysBase;
  74. struct DosLibrary    *DOSBase;
  75. struct GfxBase        *GfxBase;
  76. struct Library        *IFFParseBase;
  77.  
  78.     /* Channel allocation scheme is as follows:
  79.      *
  80.      *    1) Allocate two stereo channels
  81.      *    2) Allocate any left channel
  82.      *    3) Allocate any right channel
  83.      */
  84.  
  85. UBYTE AnyChannel[] =
  86. {
  87.     LEFT0F | RIGHT0F,
  88.     LEFT0F | RIGHT1F,
  89.     LEFT1F | RIGHT0F,
  90.     LEFT1F | RIGHT1F,
  91.  
  92.     LEFT0F,    LEFT1F,
  93.     RIGHT0F,LEFT1F
  94. };
  95.  
  96.     /* Prototypes for this module. */
  97.  
  98. LONG __saveds    Main(VOID);
  99. VOID __regargs    StartSound(struct IOAudio **Audio,LONG Rate,LONG Volume,APTR Data,LONG Length,BYTE Stereo);
  100. VOID __regargs    WaitSound(struct IOAudio **Audio,BYTE Stereo);
  101. VOID __regargs    StopSound(struct IOAudio **Audio,BYTE Stereo);
  102. VOID __regargs    HandleSound(STRPTR Name,struct IOAudio **Audio,APTR *AudioData,LONG BufferSize,BYTE Stereo);
  103. BYTE __regargs    PlayIt(STRPTR Name,LONG BufferSize);
  104.  
  105.  
  106.     /* Main():
  107.      *
  108.      *    The program entry point.
  109.      */
  110.  
  111. LONG __saveds
  112. Main()
  113. {
  114.     struct WBStartup    *WBenchMsg;
  115.     LONG             Result = RETURN_FAIL;
  116.     struct Process        *ThisProcess;
  117.     LONG             Pri;
  118.     LONG             BufferSize = 5000;
  119.  
  120.         /* Set up ExecBase */
  121.  
  122.     SysBase = *(struct ExecBase **)4;
  123.  
  124.         /* Pick up current process identifier. */
  125.  
  126.     ThisProcess = (struct Process *)SysBase -> ThisTask;
  127.  
  128.         /* If no CLI info is present, wait for Workbench
  129.          * startup message.
  130.          */
  131.  
  132.     if(!ThisProcess -> pr_CLI)
  133.     {
  134.         WaitPort(&ThisProcess -> pr_MsgPort);
  135.  
  136.         WBenchMsg = (struct WBStartup *)GetMsg(&ThisProcess -> pr_MsgPort);
  137.     }
  138.     else
  139.         WBenchMsg = NULL;
  140.  
  141.         /* Determine current priority. */
  142.  
  143.     Pri = ThisProcess -> pr_Task . tc_Node . ln_Pri;
  144.  
  145.         /* If lower than 20, set the current process priority to 20. */
  146.  
  147.     if(Pri < 20)
  148.         SetTaskPri(ThisProcess,20);
  149.  
  150.         /* Open dos.library. */
  151.  
  152.     if(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37))
  153.     {
  154.             /* Open graphics.library */
  155.  
  156.         if(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",37))
  157.         {
  158.                 /* Open iffparse.library. */
  159.  
  160.             if(IFFParseBase = OpenLibrary("iffparse.library",37))
  161.             {
  162.                     /* If started from Workbench, play the
  163.                      * sound files passed to us via project
  164.                      * icons.
  165.                      */
  166.  
  167.                 if(WBenchMsg)
  168.                 {
  169.                     LONG i;
  170.  
  171.                         /* Run down the list... */
  172.  
  173.                     for(i = 1 ; i < WBenchMsg -> sm_NumArgs ; i++)
  174.                     {
  175.                             /* If a lock and a name is present, change
  176.                              * to the project's home directory and try
  177.                              * to play the sound file.
  178.                              */
  179.  
  180.                         if(WBenchMsg -> sm_ArgList[i] . wa_Lock && WBenchMsg -> sm_ArgList[i] . wa_Name)
  181.                         {
  182.                             CurrentDir(WBenchMsg -> sm_ArgList[i] . wa_Lock);
  183.  
  184.                             PlayIt(WBenchMsg -> sm_ArgList[i] . wa_Name,BufferSize);
  185.                         }
  186.                     }
  187.                 }
  188.                 else
  189.                 {
  190.                     struct AnchorPath *Anchor;
  191.  
  192.                         /* Allocate memory for pattern matching buffer. */
  193.  
  194.                     if(Anchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath) + 512,MEMF_ANY | MEMF_CLEAR))
  195.                     {
  196.                         STRPTR         Args[ARG_COUNT] = { NULL, NULL };
  197.                         struct RDArgs    *ArgsPtr;
  198.  
  199.                             /* The scanning process is to
  200.                              * be aborted by pressing ^C.
  201.                              */
  202.  
  203.                         Anchor -> ap_BreakBits    = SIGBREAKF_CTRL_C;
  204.                         Anchor -> ap_Strlen    = 512;
  205.  
  206.                             /* Read the arguments... */
  207.  
  208.                         if(ArgsPtr = ReadArgs("Pattern,Buffer/K/N",(LONG *)Args,NULL))
  209.                         {
  210.                             LONG Error = 0;
  211.  
  212.                                 /* Did we get a pattern to look for? */
  213.  
  214.                             if(Args[ARG_PATTERN])
  215.                             {
  216.                                 BYTE MatchMade = FALSE;
  217.  
  218.                                 Result = RETURN_OK;
  219.  
  220.                                     /* Are we to use a special replay
  221.                                      * buffer size?
  222.                                      */
  223.  
  224.                                 if(Args[ARG_BUFFERSIZE])
  225.                                 {
  226.                                     BufferSize = *(LONG *)Args[ARG_BUFFERSIZE];
  227.  
  228.                                         /* 1000 bytes is the minimum. */
  229.  
  230.                                     if(BufferSize < 1000)
  231.                                         BufferSize = 1000;
  232.                                 }
  233.  
  234.                                     /* Look for the first file/directory to match the pattern. */
  235.  
  236.                                 if(!MatchFirst(Args[ARG_PATTERN],Anchor))
  237.                                 {
  238.                                     STRPTR Name = Anchor -> ap_Buf;
  239.  
  240.                                     for(;;)
  241.                                     {
  242.                                             /* Did we find a file or a directory? */
  243.  
  244.                                         if(Anchor -> ap_Info . fib_DirEntryType < 0)
  245.                                         {
  246.                                             MatchMade = TRUE;
  247.  
  248.                                                 /* Play the sound file. */
  249.  
  250.                                             if(!PlayIt(Name,BufferSize))
  251.                                             {
  252.                                                 Printf("PlaySound: Error during channel allocation!\n");
  253.  
  254.                                                 Result = RETURN_ERROR;
  255.  
  256.                                                 break;
  257.                                             }
  258.  
  259.                                                 /* Check for abort signal. */
  260.  
  261.                                             if(SetSignal(0,0) & SIGBREAKF_CTRL_C)
  262.                                             {
  263.                                                 SetSignal(0,SIGBREAKF_CTRL_C);
  264.  
  265.                                                 PrintFault(ERROR_BREAK,"PlaySound");
  266.  
  267.                                                 Result = RETURN_WARN;
  268.  
  269.                                                 break;
  270.                                             }
  271.                                         }
  272.  
  273.                                             /* Scan for the next matching file name. */
  274.  
  275.                                         if(MatchNext(Anchor))
  276.                                         {
  277.                                             Error = IoErr();
  278.  
  279.                                             if(Error && Error != ERROR_NO_MORE_ENTRIES)
  280.                                             {
  281.                                                 PrintFault(Error,"PlaySound");
  282.  
  283.                                                 if(Error == ERROR_BREAK)
  284.                                                     Result = RETURN_WARN;
  285.                                                 else
  286.                                                     Result = RETURN_ERROR;
  287.                                             }
  288.  
  289.                                             break;
  290.                                         }
  291.                                     }
  292.  
  293.                                         /* Free pattern matching auxilary data. */
  294.  
  295.                                     MatchEnd(Anchor);
  296.                                 }
  297.                                 else
  298.                                 {
  299.                                     Error = IoErr();
  300.  
  301.                                     if(Error && Error != ERROR_NO_MORE_ENTRIES)
  302.                                     {
  303.                                         PrintFault(Error,"PlaySound");
  304.  
  305.                                         if(Error == ERROR_BREAK)
  306.                                             Result = RETURN_WARN;
  307.                                         else
  308.                                             Result = RETURN_ERROR;
  309.                                     }
  310.                                 }
  311.  
  312.                                     /* Did we find any matching files? */
  313.  
  314.                                 if(!MatchMade && !Error)
  315.                                 {
  316.                                     Printf("PlaySound: No matching files were found.\n");
  317.  
  318.                                     Result = RETURN_WARN;
  319.                                 }
  320.                             }
  321.                             else
  322.                                 PrintFault(ERROR_REQUIRED_ARG_MISSING,"PlaySound");
  323.  
  324.                                 /* Free argument parser data. */
  325.  
  326.                             FreeArgs(ArgsPtr);
  327.                         }
  328.  
  329.                             /* Free pattern matching buffer. */
  330.  
  331.                         FreeVec(Anchor);
  332.                     }
  333.                 }
  334.  
  335.                     /* Clean up... */
  336.  
  337.                 CloseLibrary(IFFParseBase);
  338.             }
  339.             else
  340.             {
  341.                 if(ThisProcess -> pr_CLI)
  342.                     Printf("PlaySound: Failed to open iffparse.library!\a\n");
  343.             }
  344.  
  345.             CloseLibrary(GfxBase);
  346.         }
  347.         else
  348.         {
  349.             if(ThisProcess -> pr_CLI)
  350.                 Printf("PlaySound: Failed to open graphics.library!\a\n");
  351.         }
  352.  
  353.         CloseLibrary(DOSBase);
  354.     }
  355.  
  356.         /* If started from Workbench, reply the startup message. */
  357.  
  358.     if(WBenchMsg)
  359.     {
  360.         Forbid();
  361.  
  362.         ReplyMsg(&WBenchMsg -> sm_Message);
  363.     }
  364.  
  365.         /* Reset the task priority. */
  366.  
  367.     SetTaskPri(ThisProcess,Pri);
  368.  
  369.         /* Return success. */
  370.  
  371.     return(Result);
  372. }
  373.  
  374.     /* StartSound():
  375.      *
  376.      *    Play a sound, play it in stereo if possible.
  377.      */
  378.  
  379. VOID __regargs
  380. StartSound(struct IOAudio **Audio,LONG Rate,LONG Volume,APTR Data,LONG Length,BYTE Stereo)
  381. {
  382.         /* Set up the left channel. */
  383.  
  384.     Audio[AUDIO_LEFT] -> ioa_Request . io_Command    = CMD_WRITE;
  385.     Audio[AUDIO_LEFT] -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  386.     Audio[AUDIO_LEFT] -> ioa_Period            = Rate;
  387.     Audio[AUDIO_LEFT] -> ioa_Volume            = Volume;
  388.     Audio[AUDIO_LEFT] -> ioa_Cycles            = 1;
  389.     Audio[AUDIO_LEFT] -> ioa_Data            = Data;
  390.     Audio[AUDIO_LEFT] -> ioa_Length            = Length;
  391.  
  392.         /* Are we to play the sound in stereo? */
  393.  
  394.     if(Stereo)
  395.     {
  396.             /* To avoid echoes or delays, we will synchronize
  397.              * both channels. To do the trick, we stop audio
  398.              * output until both audio IO requests are running
  399.              * and start them both at the same time using CMD_START.
  400.              */
  401.  
  402.         Audio[AUDIO_CONTROL] -> ioa_Request . io_Command = CMD_STOP;
  403.  
  404.         DoIO(Audio[AUDIO_CONTROL]);
  405.  
  406.             /* Set up the right channel. */
  407.  
  408.         Audio[AUDIO_RIGHT] -> ioa_Request . io_Command    = CMD_WRITE;
  409.         Audio[AUDIO_RIGHT] -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  410.         Audio[AUDIO_RIGHT] -> ioa_Period        = Rate;
  411.         Audio[AUDIO_RIGHT] -> ioa_Volume        = Volume;
  412.         Audio[AUDIO_RIGHT] -> ioa_Cycles        = 1;
  413.         Audio[AUDIO_RIGHT] -> ioa_Data            = Data;
  414.         Audio[AUDIO_RIGHT] -> ioa_Length        = Length;
  415.  
  416.             /* Start both audio IO requests. */
  417.  
  418.         BeginIO(Audio[AUDIO_LEFT]);
  419.         BeginIO(Audio[AUDIO_RIGHT]);
  420.  
  421.             /* Cause audio.device to play the sound on two
  422.              * stereo channels.
  423.              */
  424.  
  425.         Audio[AUDIO_CONTROL] -> ioa_Request . io_Command = CMD_START;
  426.  
  427.         DoIO(Audio[AUDIO_CONTROL]);
  428.     }
  429.     else
  430.         BeginIO(Audio[AUDIO_LEFT]);
  431. }
  432.  
  433.     /* WaitSound(struct IOAudio **Audio,BYTE Stereo):
  434.      *
  435.      *    Wait for sound to stop.
  436.      */
  437.  
  438. VOID __regargs
  439. WaitSound(struct IOAudio **Audio,BYTE Stereo)
  440. {
  441.     WaitIO(Audio[AUDIO_LEFT]);
  442.  
  443.     if(Stereo)
  444.         WaitIO(Audio[AUDIO_RIGHT]);
  445. }
  446.  
  447.     /* StopSound(struct IOAudio **Audio,BYTE Stereo):
  448.      *
  449.      *    Abort any sound currently playing.
  450.      */
  451.  
  452. VOID __regargs
  453. StopSound(struct IOAudio **Audio,BYTE Stereo)
  454. {
  455.     if(!CheckIO(Audio[AUDIO_LEFT]))
  456.         AbortIO(Audio[AUDIO_LEFT]);
  457.  
  458.     if(Stereo)
  459.     {
  460.         if(!CheckIO(Audio[AUDIO_RIGHT]))
  461.             AbortIO(Audio[AUDIO_RIGHT]);
  462.  
  463.         WaitIO(Audio[AUDIO_LEFT]);
  464.         WaitIO(Audio[AUDIO_RIGHT]);
  465.     }
  466.     else
  467.         WaitIO(Audio[AUDIO_LEFT]);
  468. }
  469.  
  470.     /* HandleSound():
  471.      *
  472.      *    Play a sound using double-buffering.
  473.      */
  474.  
  475. VOID __regargs
  476. HandleSound(STRPTR Name,struct IOAudio **Audio,APTR *AudioData,LONG BufferSize,BYTE Stereo)
  477. {
  478.     struct IFFHandle    *Handle;
  479.     struct StoredProperty    *Prop;
  480.     struct Voice8Header    *VoiceHeader;
  481.  
  482.     LONG             Rate,
  483.                  Length,
  484.                  Volume;
  485.  
  486.         /* Allocate an IFF handle. */
  487.  
  488.     if(Handle = AllocIFF())
  489.     {
  490.             /* Open the sound file for reading. */
  491.  
  492.         if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
  493.         {
  494.                 /* Say it's a plain AmigaDOS file that we
  495.                  * are about to read.
  496.                  */
  497.  
  498.             InitIFFasDOS(Handle);
  499.  
  500.                 /* Open the file for reading. */
  501.  
  502.             if(!OpenIFF(Handle,IFFF_READ))
  503.             {
  504.                     /* Remember the voice header chunk if encountered. */
  505.  
  506.                 if(!PropChunk(Handle,'8SVX','VHDR'))
  507.                 {
  508.                         /* Stop in front of the data body chunk. */
  509.  
  510.                     if(!StopChunk(Handle,'8SVX','BODY'))
  511.                     {
  512.                             /* Scan the file... */
  513.  
  514.                         if(!ParseIFF(Handle,IFFPARSE_SCAN))
  515.                         {
  516.                                 /* Try to find the voice header chunk. */
  517.  
  518.                             if(Prop = FindProp(Handle,'8SVX','VHDR'))
  519.                             {
  520.                                 VoiceHeader = (struct Voice8Header *)Prop -> sp_Data;
  521.  
  522.                                     /* No compression and only a single octave, please! */
  523.  
  524.                                 if(!VoiceHeader -> sCompression && VoiceHeader -> ctOctave == 1)
  525.                                 {
  526.                                     struct ContextNode *ContextNode;
  527.  
  528.                                         /* Get information on the current chunk. */
  529.  
  530.                                     if(ContextNode = CurrentChunk(Handle))
  531.                                     {
  532.                                         LONG    Bytes    = 0;
  533.                                         BYTE    Played    = FALSE,
  534.                                             Buffer    = 0;
  535.  
  536.                                             /* Play either the one-shot or the repeat part,
  537.                                              * but not both.
  538.                                              */
  539.  
  540.                                         Length    = VoiceHeader -> oneShotHiSamples ? VoiceHeader -> oneShotHiSamples : VoiceHeader -> repeatHiSamples;
  541.  
  542.                                             /* Determine replay rate. */
  543.  
  544.                                         Rate    = (GfxBase -> DisplayFlags & PAL ? 3546895 : 3579545) / VoiceHeader -> samplesPerSec;
  545.  
  546.                                             /* Determine replay volume. */
  547.  
  548.                                         Volume    = (VoiceHeader -> volume * 64) / 0x10000;
  549.  
  550.                                             /* Start playing... */
  551.  
  552.                                         while(Length)
  553.                                         {
  554.                                                 /* Are we to abort the playing process? */
  555.  
  556.                                             if(SetSignal(0,0) & SIGBREAKF_CTRL_C)
  557.                                             {
  558.                                                 if(Played)
  559.                                                 {
  560.                                                     StopSound(Audio,Stereo);
  561.  
  562.                                                     Played = FALSE;
  563.                                                 }
  564.  
  565.                                                 break;
  566.                                             }
  567.  
  568.                                                 /* Are we to abort the current sound? */
  569.  
  570.                                             if(SetSignal(0,0) & SIGBREAKF_CTRL_D)
  571.                                             {
  572.                                                 SetSignal(0,SIGBREAKF_CTRL_D);
  573.  
  574.                                                 if(Played)
  575.                                                 {
  576.                                                     StopSound(Audio,Stereo);
  577.  
  578.                                                     Played = FALSE;
  579.                                                 }
  580.  
  581.                                                 break;
  582.                                             }
  583.  
  584.                                                 /* Determine number of bytes to read. */
  585.  
  586.                                             if(Length < BufferSize)
  587.                                                 Bytes = Length;
  588.                                             else
  589.                                                 Bytes = BufferSize;
  590.  
  591.                                             Length -= Bytes;
  592.  
  593.                                                 /* Read the following data. */
  594.  
  595.                                             if(ReadChunkBytes(Handle,AudioData[Buffer],Bytes) != Bytes)
  596.                                                 break;
  597.                                             else
  598.                                             {
  599.                                                     /* If still playing, wait until
  600.                                                      * the previous sound has finished.
  601.                                                      */
  602.  
  603.                                                 if(Played)
  604.                                                     WaitSound(Audio,Stereo);
  605.  
  606.                                                 StartSound(Audio,Rate,Volume,AudioData[Buffer],Bytes,Stereo);
  607.  
  608.                                                     /* Remember that we have been active. */
  609.  
  610.                                                 Played = TRUE;
  611.  
  612.                                                     /* Toggle the buffer to play/read. */
  613.  
  614.                                                 Buffer ^= 1;
  615.                                             }
  616.                                         }
  617.  
  618.                                             /* Wait until the sound is finished. */
  619.  
  620.                                         if(Played)
  621.                                             WaitSound(Audio,Stereo);
  622.                                     }
  623.                                 }
  624.                             }
  625.                         }
  626.                     }
  627.                 }
  628.  
  629.                     /* Close the IFF read handle. */
  630.  
  631.                 CloseIFF(Handle);
  632.             }
  633.  
  634.                 /* Close the file. */
  635.  
  636.             Close(Handle -> iff_Stream);
  637.         }
  638.  
  639.             /* Free the handle data. */
  640.  
  641.         FreeIFF(Handle);
  642.     }
  643. }
  644.  
  645.     /* PlayIt(STRPTR Name,LONG BufferSize):
  646.      *
  647.      *    Do the setups necessary to play a sound.
  648.      */
  649.  
  650. BYTE __regargs
  651. PlayIt(STRPTR Name,LONG BufferSize)
  652. {
  653.     BYTE *AudioData[2],Result = FALSE;
  654.  
  655.         /* Allocate the audio buffer. */
  656.  
  657.     if(AudioData[0] = AllocVec(BufferSize * 2,MEMF_CHIP))
  658.     {
  659.         struct MsgPort *AudioPort;
  660.  
  661.             /* Split the audio buffer in two. */
  662.  
  663.         AudioData[1] = AudioData[0] + BufferSize;
  664.  
  665.             /* Create the IO request reply port. */
  666.  
  667.         if(AudioPort = CreateMsgPort())
  668.         {
  669.             struct IOAudio *Audio[AUDIO_COUNT];
  670.  
  671.                 /* Allocate the audio IO requests. */
  672.  
  673.             if(Audio[AUDIO_LEFT] = (struct IOAudio *)AllocVec(sizeof(struct IOAudio) * AUDIO_COUNT,MEMF_PUBLIC | MEMF_CLEAR))
  674.             {
  675.                     /* Cut the pie into three pieces. */
  676.  
  677.                 Audio[AUDIO_RIGHT]    = Audio[AUDIO_LEFT] + 1;
  678.                 Audio[AUDIO_CONTROL]    = Audio[AUDIO_RIGHT] + 1;
  679.  
  680.                     /* Open audio.device, allocate the channels on the fly. */
  681.  
  682.                 Audio[AUDIO_LEFT] -> ioa_Request . io_Message . mn_Node . ln_Type    = NT_MESSAGE;
  683.                 Audio[AUDIO_LEFT] -> ioa_Request . io_Message . mn_Length        = sizeof(struct IOAudio);
  684.                 Audio[AUDIO_LEFT] -> ioa_Request . io_Command                = ADCMD_ALLOCATE;
  685.                 Audio[AUDIO_LEFT] -> ioa_Request . io_Flags                = ADIOF_NOWAIT;
  686.                 Audio[AUDIO_LEFT] -> ioa_Data                        = AnyChannel;
  687.                 Audio[AUDIO_LEFT] -> ioa_Length                        = sizeof(AnyChannel);
  688.                 Audio[AUDIO_LEFT] -> ioa_Request . io_Message . mn_ReplyPort        = AudioPort;
  689.  
  690.                 if(!OpenDevice(AUDIONAME,0,Audio[AUDIO_LEFT],0))
  691.                 {
  692.                     WORD Count,i;
  693.  
  694.                         /* Check whether we got just a single
  695.                          * or two separate stereo channels.
  696.                          */
  697.  
  698.                     for(i = 0 ; i < sizeof(AnyChannel) ; i++)
  699.                     {
  700.                         if((((LONG)Audio[AUDIO_LEFT] -> ioa_Request . io_Unit) & AnyChannel[i]) == AnyChannel[i])
  701.                         {
  702.                             Count = i;
  703.  
  704.                             break;
  705.                         }
  706.                     }
  707.  
  708.                         /* Set up the three audio IO requests. */
  709.  
  710.                     for(i = AUDIO_RIGHT ; i < AUDIO_COUNT ; i++)
  711.                         CopyMem(Audio[AUDIO_LEFT],Audio[i],sizeof(struct IOAudio));
  712.  
  713.                         /* We have been successful so far. */
  714.  
  715.                     Result = TRUE;
  716.  
  717.                         /* Did we get two stereo channels? */
  718.  
  719.                     if(Count < 4)
  720.                     {
  721.                             /* Retain just the left channel. */
  722.  
  723.                         Audio[AUDIO_LEFT] -> ioa_Request . io_Unit    = (APTR)(((ULONG)Audio[AUDIO_LEFT] -> ioa_Request . io_Unit) & LEFT_MASK);
  724.  
  725.                             /* Retain just the right channel. */
  726.  
  727.                         Audio[AUDIO_RIGHT] -> ioa_Request . io_Unit    = (APTR)(((ULONG)Audio[AUDIO_RIGHT] -> ioa_Request . io_Unit) & RIGHT_MASK);
  728.  
  729.                             /* Play the sound. */
  730.  
  731.                         HandleSound(Name,Audio,(APTR *)AudioData,BufferSize,TRUE);
  732.                     }
  733.                     else
  734.                         HandleSound(Name,Audio,(APTR *)AudioData,BufferSize,FALSE);
  735.  
  736.                         /* Close the device, freeing the channels. */
  737.  
  738.                     CloseDevice(Audio[AUDIO_CONTROL]);
  739.                 }
  740.  
  741.                     /* Delete the audio request block. */
  742.  
  743.                 FreeVec(Audio[AUDIO_LEFT]);
  744.             }
  745.  
  746.                 /* Delete the audio IO request reply port. */
  747.  
  748.             DeleteMsgPort(AudioPort);
  749.         }
  750.  
  751.             /* Free the replay buffer. */
  752.  
  753.         FreeVec(AudioData[0]);
  754.     }
  755.  
  756.     return(Result);
  757. }
  758.